package com.stylefeng.guns.common.plugin.service.impl;

import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.collect.Sets;
import com.stylefeng.guns.common.exception.BizExceptionEnum;
import com.stylefeng.guns.common.exception.BussinessException;
import com.stylefeng.guns.common.plugin.entity.BaseModel;
import com.stylefeng.guns.common.plugin.entity.Treeable;
import com.stylefeng.guns.common.plugin.service.IBaseTreeableService;
import com.stylefeng.guns.core.node.ZTreeNode;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public abstract class BaseTreeableServiceImpl<M extends BaseMapper<T>, T extends BaseModel & Treeable>
        extends ServiceImpl<M, T> implements IBaseTreeableService<T> {

    @Transactional
    public void deleteSelfAndChild(Integer id) {
        T t = super.baseMapper.selectById(id);
        Wrapper<T> wrapper = new EntityWrapper<>();
        wrapper.eq("id", t.getId()).or("pids like '" + t.makeSelfAsNewParentIds() + "%'");
        super.baseMapper.delete(wrapper);
    }

    public Integer addNode(T t) {
        setPids(t);
        return super.baseMapper.insert(t);
    }


    private List<T> findChildren(T t) {
        String pids = t.makeSelfAsNewParentIds();
        Wrapper wrapper = new EntityWrapper();
        wrapper.like("pids", pids + "%");
        return super.selectList(wrapper);
    }

    public Set<Integer> findChildrenIds(Integer id) {
        Set<Integer> set = Sets.newHashSet();
        T parent = selectById(id);
        List<T> list = findChildren(parent);
        for (T children : list) {
            set.add(children.getId());

        }
        return set;
    }

    public List<ZTreeNode> tree(Wrapper<T> wrapper) {
        List<T> list = super.baseMapper.selectList(wrapper);
        List<ZTreeNode> treeNodeList = new ArrayList<>();
        for (T t : list) {
            ZTreeNode node = new ZTreeNode();
//            node.setChecked(true);
            treeNodeList.add(node);
            node.setpId(t.getPid() + "");
            try {
                BeanUtils.copyProperties(node, t);
                if (t.getPid() == null || t.getPid().equals(0)) {
                    node.setIsOpen(true);
                } else {
                    node.setIsOpen(false);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        treeNodeList.add(ZTreeNode.createParent());
        return treeNodeList;
    }

    public List<ZTreeNode> tree() {
        return tree(null);
    }

    @Transactional
    public void updateNode(T t) {
        T old = super.selectById(t.getId());
        //pid不变
        if (t.getPid().equals(old.getPid())) {
            t.updateById();
            return;
        }
        //pid是其本身
        if (t.getPid().equals(t.getId())) {
            throw new BussinessException(BizExceptionEnum.PARENT_IS_SELF_OR_CHILD);
        }

        //pid为其子节点
        T newParent = super.selectById(t.getPid());
        if (newParent.getPids().startsWith(old.makeSelfAsNewParentIds())) {
            throw new BussinessException(BizExceptionEnum.PARENT_IS_SELF_OR_CHILD);
        }

        //设置父节点们
        setPids(t);
        t.updateById();

        //修改其子节点的pids
        Wrapper<T> wrapper = new EntityWrapper<>();
        wrapper.like("pids", old.makeSelfAsNewParentIds() + "%");
        List<T> children = this.selectList(wrapper);
        for (T child : children) {
            setPids(child,t);
            child.updateById();
        }
    }

    public void setPids(T t, T parent) {
        t.setPids(parent.makeSelfAsNewParentIds());
    }


    public void setPids(T t) {
        if (0 == t.getPid() || t.getPid() == null) {
            t.setPids("0" + t.getSeparator());
        } else {
            T parent = super.baseMapper.selectById(t.getPid());
            setPids(t, parent);
        }
    }

}
